<script lang="ts" setup name="ProcessDesigner">
import { computed, nextTick, onBeforeMount, onBeforeUnmount, onMounted, ref, type Ref } from "vue";
import ProcessRender from "./ProcessRender.vue";
import FlowAttr from "./config/common/FlowAttr.vue";
import ProcessView from "./ProcessView.vue";
import nodeType, { NodeComponentConfigs } from "./ProcessNodes";
import type { FlowModelNode, DefFlowModel, FlowAttrRef } from "./ProcessDef";
import { ElMessage } from "element-plus";

const props = defineProps({
  active: {
    type: Boolean,
    default: false
  },
  fullscreen: {
    type: Boolean,
    default: false
  }
});

const processDef = defineModel<DefFlowModel>("defFlow");
const flowDef = defineModel<FlowModelNode[] | undefined>();

//缩放比例
const zoom = ref(100);
//选中的节点
const activeNode = ref({ type: "", name: "" });

const showInput = ref(false);
const nodeConfVisible = ref(false);
const flowDefVisible = ref(false);
const viewerVisible = ref(false);
const taskIndex = ref<number>(0);
//流程图ref
const processRender = ref();
const flowAttrRef = ref<Ref<FlowAttrRef>>();
const processViewRef = ref(null);
const mounted = ref(false);
//是否按下ctrl
let ctrlPressed = false;

//配置面板宽度
const configWidth = computed(() => {
  return activeNode.value.type === "Exclusive" ? 600 : 500;
});

function selectNode(selNode) {
  const node = selNode.node;
  const index = selNode.taskIndex;
  activeNode.value = node;
  if (index) {
    taskIndex.value = parseInt(index);
  } else {
    taskIndex.value = 0;
  }
  if (NodeComponentConfigs[activeNode.value.type]) {
    nodeConfVisible.value = true;
  } else {
    ElMessage.warning("本节点无配置项");
  }
}

function doZoom(sc) {
  if (
    (zoom.value > 30 && zoom.value < 150) ||
    (zoom.value <= 30 && sc > 0) ||
    (zoom.value >= 150 && sc < 0)
  ) {
    zoom.value += sc;
  } else {
    ElMessage.warning("缩放已经到极限了😥");
  }
}

function keyDown(event) {
  if (event.ctrlKey) {
    ctrlPressed = true;
    document.addEventListener("wheel", mouseWheel, { passive: false });
  }
}

function keyUp(event) {
  if (event.key === "Control") {
    ctrlPressed = false;
    document.removeEventListener("wheel", mouseWheel);
  }
}

function mouseWheel(event) {
  if (ctrlPressed && props.active) {
    // 阻止默认的缩放行为
    event.preventDefault();
    // 获取滚动方向，向上为正，向下为负
    const delta = Math.sign(event.deltaY);
    doZoom(delta * -5);
  }
}

const handleReloadFlow = (flowJson, defFlow) => {
  flowDef.value = JSON.parse(flowJson);
  processDef.value = defFlow;
};

const handleOpenView = () => {
  viewerVisible.value = true;
};

onBeforeMount(() => {
  console.log("onBeforeMount", flowDef.value);
  if (flowDef.value?.length === 0) {
    flowDef.value = [nodeType.Start.create()];
  }
});

onMounted(() => {
  document.addEventListener("keydown", keyDown);
  document.addEventListener("keyup", keyUp);
  console.log("mounted flowDef", flowDef.value);
  mounted.value = true;
});

onBeforeUnmount(() => {
  document.removeEventListener("keydown", keyDown);
  document.removeEventListener("keyup", keyUp);
  document.removeEventListener("wheel", mouseWheel);
});

function validate() {
  return new Promise((resolve, reject) => {
    processRender.value
      .validate()
      .then(() => {
        resolve([]);
      })
      .catch(errs => {
        reject(errs);
      });
  });
}

function validateFlowDef() {
  nextTick(() => {
    const flowAttrRefValue = flowAttrRef.value as any;
    flowAttrRefValue?.validate();
  });
}

defineExpose({ validate, validateFlowDef });
</script>

<template>
  <div class="container-designer" v-if="active">
    <div class="container-operation-left">
      <el-button @click="handleOpenView">流程配置</el-button>
    </div>
    <div class="container-operation">
      <div class="container-operation-item">
        <el-button @click="flowDefVisible = true">流程基础属性</el-button>
        <el-button icon="ZoomOut" circle @click="doZoom(-5)" />
        <span>{{ zoom }}%</span>
        <el-button icon="ZoomIn" circle @click="doZoom(5)" />
      </div>
    </div>
    <el-scrollbar>
      <div v-if="mounted">
        <ProcessRender
          ref="processRender"
          :style="`transform: scale(${zoom / 100})`"
          v-model="flowDef"
          :readonly="false"
          @select="selectNode"
        />
        <el-drawer class="flow-drawer" :size="configWidth" v-model="flowDefVisible">
          <template #header>
            <div>
              <el-icon style="margin-right: 10px"><Edit /></el-icon>
              流程基础属性
            </div>
          </template>
          <FlowAttr
            ref="flowAttrRef"
            :modelValue="processDef"
            v-model:flowDef="flowDef"
            @reload-flow="handleReloadFlow"
          />
        </el-drawer>
        <el-drawer
          class="flow-drawer"
          :size="configWidth"
          v-model="viewerVisible"
          @close="validate"
        >
          <template #header>
            <div>
              <el-icon style="margin-right: 10px"><Edit /></el-icon>
              流程配置
            </div>
          </template>
          <ProcessView ref="processViewRef" v-model="flowDef" />
        </el-drawer>

        <el-drawer
          class="flow-drawer"
          :size="configWidth"
          :title="activeNode.name"
          v-model="nodeConfVisible"
          @close="validate"
        >
          <template #header>
            <div>
              <el-input
                v-model="activeNode.name"
                v-show="showInput"
                style="width: 300px"
                @blur="showInput = false"
              ></el-input>
              <el-link v-show="!showInput" @click="showInput = true" style="font-size: medium">
                <el-icon style="margin-right: 10px"><Edit /></el-icon>
                {{ activeNode.name }}
              </el-link>
            </div>
          </template>
          <component
            v-model="activeNode"
            :defFlow="processDef"
            :taskIndex="taskIndex"
            :is="NodeComponentConfigs[activeNode.type]"
          />
        </el-drawer>
      </div>
    </el-scrollbar>
  </div>
</template>

<style lang="scss" scoped>
@use "@/assets/style/design/flow-drawer.scss";
.container-designer {
  display: block !important;
  min-width: 100%;
  height: 100%;

  .container-operation-left {
    position: absolute;
    top: 90px;
    left: 10px;
    z-index: 99;
    width: 200px;
  }

  .container-operation {
    position: absolute;
    top: 90px;
    right: 80px;
    z-index: 99;
    width: 200px;
  }

  .container-operation-item {
    display: flex;
    align-items: center;
    justify-content: space-between;

    span {
      padding: 0 5px;
      font-size: medium;
      color: var(--el-text-color-primary);
    }
  }
}
</style>
